package genericity

import (
	"newRetailByGolang/utils"
	"reflect"
	"time"
)

type E any
type M any

//type GenericUnifiedMany[E any, M any] struct {
//	Entity E
//	Many   M
//}

type GenericUnifiedMany struct {
	Entity E
	Many   M
}

//func (gum *GenericUnifiedMany[any, any]) ManyCreated(relation, pk, fk string) {
func (gum *GenericUnifiedMany) ManyCreated(relation, pk, fk string) {
	value := reflect.ValueOf(&(gum.Entity))
	reallyId := value.Elem().FieldByName("Id").Interface().(int64)

	mpValue := reflect.ValueOf(&(gum.Many))

	uw := new(utils.Worker)
	var vParams []reflect.Value
	var m_list []*M
	many_id_list := value.Elem().FieldByName(relation).Interface().([]int64)
	for _, many_id := range many_id_list {
		nMany := reflect.New(reflect.TypeOf(gum.Many))
		mValue := nMany.Elem()
		mValue.FieldByName("Id").SetInt(uw.GetId())
		mValue.FieldByName(pk).SetInt(reallyId)
		mValue.FieldByName(fk).SetInt(int64(many_id))
		mValue.FieldByName("CreatedAt").Set(reflect.ValueOf(time.Now()))
		mValue.FieldByName("UpdatedAt").Set(reflect.ValueOf(time.Now()))

		m_list = append(m_list, nMany.Interface().(*M))
	}
	vParams = append(vParams, reflect.ValueOf(m_list))

	mpValue.MethodByName("BatchInsert").Call(vParams)

	value.MethodByName("Insert").Call([]reflect.Value{value})
}

func ManyCreated[E any, M any](entity E, many M, relation, pk, fk string) {
	value := reflect.ValueOf(&entity)
	reallyId := value.Elem().FieldByName("Id").Interface().(int64)

	mpValue := reflect.ValueOf(&many)

	uw := new(utils.Worker)
	var vParams []reflect.Value
	var m_list []*M
	many_id_list := value.Elem().FieldByName(relation).Interface().([]int64)
	for _, many_id := range many_id_list {
		nMany := reflect.New(reflect.TypeOf(many))
		mValue := nMany.Elem()
		mValue.FieldByName("Id").SetInt(uw.GetId())
		mValue.FieldByName(pk).SetInt(reallyId)
		mValue.FieldByName(fk).SetInt(int64(many_id))
		mValue.FieldByName("CreatedAt").Set(reflect.ValueOf(time.Now()))
		mValue.FieldByName("UpdatedAt").Set(reflect.ValueOf(time.Now()))

		m_list = append(m_list, nMany.Interface().(*M))
	}
	vParams = append(vParams, reflect.ValueOf(m_list))

	mpValue.MethodByName("BatchInsert").Call(vParams)

	value.MethodByName("Insert").Call([]reflect.Value{value})
}

func (gum *GenericUnifiedMany) ManyDelete(relation string) {
	value := reflect.ValueOf(&(gum.Entity))
	reallyId := value.Elem().FieldByName("Id")

	mpValue := reflect.ValueOf(&(gum.Many))

	mpValue.MethodByName("BatchDelete").Call([]reflect.Value{reflect.ValueOf(relation), reallyId})

	value.MethodByName("Delete").Call([]reflect.Value{reflect.ValueOf(reallyId)})
}

func ManyDelete[E any, M any](entity E, many M, relation string) {
	value := reflect.ValueOf(&entity)
	reallyId := value.Elem().FieldByName("Id")

	mpValue := reflect.ValueOf(&many)

	mpValue.MethodByName("BatchDelete").Call([]reflect.Value{reflect.ValueOf(relation), reallyId})

	value.MethodByName("Delete").Call([]reflect.Value{reallyId})
}

//func (gum *GenericUnifiedMany[any, any]) ManyUpdate(relation, pk, fk string) {
func (gum *GenericUnifiedMany) ManyUpdate(relation, pk, fk string) {
	value := reflect.ValueOf(&(gum.Entity))
	reallyId := value.Elem().FieldByName("Id")

	mpValue := reflect.ValueOf(&(gum.Many))

	mpValue.MethodByName("BatchDelete").Call([]reflect.Value{reflect.ValueOf(utils.UnMarshal(pk)), reallyId})

	uw := new(utils.Worker)
	var vParams []reflect.Value
	var m_list []*M
	many_id_list := value.Elem().FieldByName(relation).Interface().([]int64)
	for _, many_id := range many_id_list {
		nMany := reflect.New(reflect.TypeOf(gum.Many))
		mValue := nMany.Elem()
		mValue.FieldByName("Id").SetInt(uw.GetId())
		mValue.FieldByName(pk).SetInt(reallyId.Interface().(int64))
		mValue.FieldByName(fk).SetInt(int64(many_id))
		mValue.FieldByName("CreatedAt").Set(reflect.ValueOf(time.Now()))
		mValue.FieldByName("UpdatedAt").Set(reflect.ValueOf(time.Now()))

		m_list = append(m_list, nMany.Interface().(*M))
	}
	vParams = append(vParams, reflect.ValueOf(m_list))

	mpValue.MethodByName("BatchInsert").Call(vParams)

	value.MethodByName("Update").Call([]reflect.Value{value})
}

func ManyUpdate[E any, M any](entity E, many M, relation, pk, fk string) {
	value := reflect.ValueOf(&entity)
	reallyId := value.Elem().FieldByName("Id")

	mpValue := reflect.ValueOf(&many)

	mpValue.MethodByName("BatchDelete").Call([]reflect.Value{reflect.ValueOf(utils.UnMarshal(pk)), reallyId})

	uw := new(utils.Worker)
	var vParams []reflect.Value
	var m_list []*M
	many_id_list := value.Elem().FieldByName(relation).Interface().([]int64)
	for _, many_id := range many_id_list {
		nMany := reflect.New(reflect.TypeOf(many))
		mValue := nMany.Elem()
		mValue.FieldByName("Id").SetInt(uw.GetId())
		mValue.FieldByName(pk).SetInt(reallyId.Interface().(int64))
		mValue.FieldByName(fk).SetInt(int64(many_id))
		mValue.FieldByName("CreatedAt").Set(reflect.ValueOf(time.Now()))
		mValue.FieldByName("UpdatedAt").Set(reflect.ValueOf(time.Now()))

		m_list = append(m_list, nMany.Interface().(*M))
	}
	vParams = append(vParams, reflect.ValueOf(m_list))

	mpValue.MethodByName("BatchInsert").Call(vParams)

	value.MethodByName("Update").Call([]reflect.Value{value})
}

func GenerityMapTest[K, V any](i interface{}) map[string][]*V {
	value := reflect.ValueOf(i).Interface().(map[string][]*V)
	return value
}













